//
// Created by mmuee on 2023/10/10.
//

#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include "FileSystem.hpp"

NS_FS_BEGIN

int renameFile(const std::string& src, const std::string& dest)
{
    return rename(src.c_str(), dest.c_str());
}

int removeFile(const std::string& src)
{
    return remove(src.c_str());
}

bool exists(const std::string& path)
{
    return access(path.c_str(), F_OK) == 0;
}

bool copyFile(const std::string& src, const std::string& dst)
{
    std::ifstream stream_src(src, std::ios::binary | std::ios::in);
    std::ofstream stream_dst(dst, std::ios::binary | std::ios::out);

    if (stream_src.is_open())
    {
        char buffer[2048];
        while (!stream_src.eof())
        {
            stream_src.read(buffer, 2048);
            stream_dst.write(buffer, stream_src.gcount());
        }
        stream_src.close();
        stream_dst.close();
    }
    return true;
}

std::vector<std::string> readdir(const std::string& path, bool onlyFile)
{
    std::vector<std::string> files{};
    DIR* dir = opendir(path.c_str());
    if (dir == nullptr)
    {
        LOG_WARN() << "Open Dir failed! dir is null";
        return files;
    }
    struct dirent* dp;

    while ((dp = readdir(dir)) != nullptr)
    {
        std::string dirName = dp->d_name;
        if (dirName == "." || dirName == "..")
        {
            continue;
        }
        else if (dp->d_type == DT_REG ||
                 (dp->d_type == DT_DIR && !onlyFile)) // file
        {
            files.emplace_back(dirName);
        }
        else
        {
            continue;
        }
    }
    closedir(dir);
    return files;
}

bool readTextFromFile(std::string& text, const char* file)
{
    text.clear();
    std::ifstream stream(file, std::ios::binary | std::ios::in);
    if (stream.is_open())
    {
        std::streampos start = stream.tellg();
        stream.seekg(0, std::ios::end);
        std::streampos end = stream.tellg();
        stream.seekg(0, std::ios::beg);
        auto fileSize = end - start;
        text.resize(uint32_t(fileSize));
        stream.read(text.data(), fileSize);
        stream.close();
        return true;
    }
    return false;
}

bool writeTextToFile(const std::string& text, const std::string& file)
{
    std::ofstream out(file);
    auto cstr = text.c_str();
    out.write(cstr, text.size());
    out.close();
    return true;
}

//bool writeJSONToFile(const JSON& json, const std::string& file,
//                     int32_t indent /** = -1 */)
//{
//    std::ofstream out(file);
//    auto str = json.dump(indent);
//    auto cstr = str.c_str();
//    out.write(cstr, str.size());
//    out.close();
//    return true;
//}
//
//bool readJSONToFile(JSON& json, const std::string& file)
//{
//    std::string text{};
//    readTextFromFile(text, file.c_str());
//    if (text.empty())
//        return false;
//
//    json = JSON::parse(text.data());
//    return true;
//}

static int _mkdir(const char* dirname)
{
    if (fs::exists(dirname))
    {
        return 0;
    }
    return mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
}

bool makeDir(const std::string& name)
{
    // 检测文件夹是否存在
    if (fs::exists(name))
    {
        return true;
    }
    char* path = strdup(name.c_str());
    char* ptr = strchr(path + 1, '/');
    do
    {
        for (; ptr; *ptr = '/', ptr = strchr(ptr + 1, '/'))
        {
            *ptr = '\0';
            if (_mkdir(path) != 0)
            { // 创建文件夹
                break;
            }
        }
        if (ptr != nullptr)
        {
            break;
        }
        else if (_mkdir(path) != 0)
        {
            break;
        }
        free(path);
        return true;
    }
    while (false);
    free(path);
    return false;
}

std::string joinPath(const std::string& path, const std::string& filename)
{
    if (path.back() == '/' && filename.front() == '/')
    {
        auto tmpPath = path;
        tmpPath.pop_back();
        return tmpPath + filename;
    }
    else if (path.back() != '/' && filename.front() != '/')
    {
        return path + '/' + filename;
    }
    else
    {
        return path + filename;
    }
}

NS_FS_END
